<template>
  <div class='app-container'>
    <div ref="graphContainer" class="parent-wrapper" style="overflow: hidden;width: calc(100% - 50px)" />
    <div class="tool-wra"></div>
  </div>
</template>

<script>
import mxgraph from '@utils/init.js';

import all_svg from '@/assets/tool_svg'
import $ from 'jquery'

import keyDown from '@utils/initKeyHandler.js'

export default {
  name: '',
  module_index: 700,
  module_name: '工具栏·SVG',
  data() {
    return {
      all_svg,
      graph: null,
      parent: null,
      num: 0,
      // 构造一个事件处理程序，该处理程序使用橡皮筋选择来选择图中的矩形区域。
      rubberBand: null,


      /**
      * 这个参数表示工具栏中的单个工具元素被拖拽时预览图的偏移位置
      * 也表示拖拽结束时创建的工具实例和鼠标之间的偏移位置
      * 合理设置可以让鼠标定位在预览图和实例的中间
      */
      cell_offset: {
        x: 0,
        y: 0,
      },
    };
  },
  created() { },
  mounted() {
    // 初始化画布
    this.init();
    // 添加过个工具栏
    all_svg.forEach((item,i) => this.inittool(i));
    // 给工具栏控制区域添加点击事件
    this.addToolClick();
    // 给单元格模型的原型挂载change事件尝试改变背景图大小
    this.changeMxgraphPrototype();
    // 初始化键盘事件
    this.initKeyHandler();
    keyDown(this.graph);
    console.log(all_svg)
  },
  methods: {
    init() {
      // 创建全局容器
      this.graph = new mxGraph(this.$refs.graphContainer);

      // 创建全局父元素
      this.parent = this.graph.getDefaultParent();

      mxEvent.disableContextMenu(this.$refs.graphContainer);    // 右键上下文禁用
      this.rubberBand = new mxRubberband(this.graph)            // 拖拽框选

      // 设置可连接
      this.graph.setConnectable(true);

      // 创建通用样式，否则无法显示SVG
      this.graph.getStylesheet().putCellStyle('myStyleSvg',{
        // 可能的值都是带有形状前缀的常量或任何新定义的形状名称
        [mxConstants.STYLE_SHAPE]: mxConstants.SHAPE_LABEL,
        [mxConstants.STYLE_PERIMETER]: mxPerimeter.RectanglePerimeter,
        [mxConstants.STYLE_ROUNDED]: true,
        [mxConstants.STYLE_ARCSIZE]: 6, // 设置圆角程度

        [mxConstants.STYLE_STROKECOLOR]: 'transparent', // 边框颜色
        [mxConstants.STYLE_FONTCOLOR]: '#333333',
        [mxConstants.STYLE_FILLCOLOR]: 'transparent', // 背景色
        [mxConstants.STYLE_LABEL_BACKGROUNDCOLOR]: '#e6e6e6',

        [mxConstants.STYLE_ALIGN]: mxConstants.ALIGN_CENTER,
        [mxConstants.STYLE_VERTICAL_ALIGN]: mxConstants.ALIGN_CENTER,
        [mxConstants.STYLE_IMAGE_ALIGN]: mxConstants.ALIGN_CENTER,
        [mxConstants.STYLE_IMAGE_VERTICAL_ALIGN]: mxConstants.ALIGN_CENTER,

        // [mxConstants.STYLE_IMAGE]: this.all_svg[0],
        [mxConstants.STYLE_IMAGE_WIDTH]: '130',     // 图片宽度
        [mxConstants.STYLE_IMAGE_HEIGHT]: '130',    // 图片高度
        // 该值表示添加到顶点标签顶部的间隔(以像素为单位)(样式仅适用于顶点)。
        [mxConstants.STYLE_SPACING_TOP]: '110',
        // 该值表示添加到顶点标签的每边的间距(以像素为单位)(样式仅适用于顶点)
        [mxConstants.STYLE_SPACING]: '8'
      });
    },
    // 创建键盘事件
    initKeyHandler() {
      // 初始化键盘事件监听
      this.keyHandler = new mxKeyHandler(this.graph);
      this.keyHandler.bindKey(46,() => {
        this.graph.removeCells(this.graph.getSelectionCells())
      })
    },
    // 给单元格模型的原型挂载事件尝试改变背景图大小
    changeMxgraphPrototype() {
      mxGraph.prototype.resizeCells = function (cells,bounds) {
        let tmp = cells[0].style.split(';');
        // tmp[0]是原有的样式集合(例如myStyleSvg),tmp[1]是背景图的路径设置
        this.getModel().setStyle(cells[0],[tmp[0],tmp[1],'imageWidth=' + bounds[0].width,'imageHeight=' + bounds[0].height].join(';'));
        this.model.beginUpdate();
        try {
          this.cellsResized(cells,bounds);
        //   this.fireEvent(new mxEventObject(mxEvent.RESIZE_CELLS,'cells',cells,'bounds',bounds));
        //   var _this = this;
        //   $.each(cells,function (i,item) {
        //     var overlays = _this.getCellOverlays(item);
        //     $.each(overlays,function (j,overlay) {
        //       if (overlay.tooltip == '辐射图') {
        //         if (ylCommon.isAllowEdit()) {
        //           overlay.offset.x = item.geometry.width - 35;
        //         } else {
        //           overlay.offset.x = item.geometry.width - 15;
        //         }
        //       }
        //       if (overlay.image.src.indexOf('lock.png') > 0) {
        //         overlay.offset.x = item.geometry.width - 15;
        //       }
        //     });
        //   });
        } finally {
          this.model.endUpdate();
        }
        return cells;
      };
    },
    // 添加工具栏的显示/隐藏事件
    addToolClick() {
      // 添加工具栏的显示/隐藏事件
      $('.tool-wra').on('click',(e) => {
        // 所点击不是span会弹出
        if (!$(e.target).hasClass('tool-wra-item')) return;

        $('.parent-wrapper>div').each((i,item) => {
          if ($(item).attr('data-index') === $(e.target).attr('data-index')) {
            if ($(e.target).hasClass('true')) {
              setTimeout(() => {
                $(item).toggleClass('true').siblings().removeClass('true');
              },500)
            } else {
              $(item).toggleClass('true').siblings().removeClass('true');
            }
            // 切换对应工具栏
            $(item).toggleClass('active').siblings().removeClass('active');
            //切换对应span
            $(e.target).toggleClass('active').siblings().removeClass('active');
          }
        })
      })
    },
    // 初始化工具栏
    inittool(tool_index) {
      // 创建一个div作为toolbar的容器
      let tbContainer = document.createElement('div');
      tbContainer.className = 'tool-item';
      // 添加供控制区使用的自定义属性data-index
      tbContainer.setAttribute('data-index',tool_index)
      // 在侧面的工具栏控制区添加控制当前工具栏的span
      $('.tool-wra').append(`
            <span class="tool-wra-item" data-index="${tool_index}">${this.all_svg[tool_index].default.name}</span><br />
        `)


      this.$refs.graphContainer.appendChild(tbContainer);

      // 创建一个mxToolbar
      let toolbar = new mxToolbar(tbContainer);
      // 指定是否处理事件。
      toolbar.enabled = false;
      // 展示当前工具栏中应展示的svg
      this.all_svg[tool_index].default.icon.forEach((item,i) => {
        // toolbar的两个官方小组件
        // toolbar.addLine();
        // toolbar.addBreak();
        // mxCell：构造在图模型中使用的新单元格。
        let vertex = new mxCell(null,new mxGeometry(0,0,130,150),'myStyleSvg;image=' + this.all_svg[tool_index].default.icon[i]);
        // 创建完善工具箱的小图标
        vertex.setVertex(true)
        let img = this.addToolbarItem(this.graph,toolbar,vertex,this.all_svg[tool_index].default.icon[i])

        // 工具箱事件
        img.enabled = true;
        // 这个事件是鼠标抬起时的事件
        this.graph.getSelectionModel().addListener(mxEvent.CHANGE,() => {
          let tmp = this.graph.isSelectionEmpty()
          // 这里的20透明度表示的是某个cell元素(节点或者边)获得焦点的时候工具栏的透明度
          mxUtils.setOpacity(img,(tmp) ? 100 : 20)
          img.enabled = tmp;
        })
      });
    },
    // 添加工具栏单项
    addToolbarItem(graph,toolbar,prototype,image) {

      // TODO:这里可能有性能问题，vertex_prototype这个变量在工具栏单项中被按下的时候会被赋值，在实例被创建的时候会被调用，按照JS的变量回收机制应该会被销毁，但是存疑，待定....
      let vertex_prototype = null;

      let funct = (graph,evt,cell,x,y) => {
        console.log('在画布中创建对应工具的实例')
        graph.stopEditing(false)
        // 通过cloneCell创建工具栏工具prototype的实例
        let vertex = graph.getModel().cloneCell(prototype)

        vertex.geometry.width = vertex_prototype.width;
        vertex.geometry.height = vertex_prototype.height;

        vertex.geometry.x = x + this.cell_offset.x + 5;  // 设置所创建实例的位置
        vertex.geometry.y = y + this.cell_offset.y + 5;

        vertex.style += ';imageWidth=' + vertex_prototype.width + ';imageHeight=' + vertex_prototype.height

        graph.addCell(vertex)   // 这一步执行在画布中进行创建
        graph.setSelectionCell(vertex)  // 这一步将新创建的单元格进行了选中
      }
      let img = toolbar.addMode(null,image,function (evt,cell) {
        // 这个回调函数貌似没什么用或者被覆盖
        let pt = this.graph.getPointForEvent(evt)

        funct(graph,evt,cell,pt.x,pt.y)
      })

      mxEvent.addListener(img,'mousedown',(evt) => {
        // 将所点击的工具的一些元素信息保存起来，在创建工具实例时会用到
        vertex_prototype = evt.target.getBoundingClientRect();
        // 设置cell_offset偏移量，让鼠标位于预览图和所创建实例的中央
        this.cell_offset.x = evt.target.getBoundingClientRect().width / 2 * -1 - 5;
        this.cell_offset.y = evt.target.getBoundingClientRect().height / 2 * -1 - 5;
        console.log(this.cell_offset)

        if (img.enabled === false) {
          // 这个if大多数时候不会被判断为true
          mxEvent.consume(evt)
        }
      })


      // mxUtils.makeDraggable：添加拖拽事件，此处是给工具栏的工具项添加拖拽事件
      /**
       * 参数一element：被添加拖拽事件的元素
       * 参数二graphF：作为拖放目标的mxGraph或接受鼠标事件并返回当前mxGraph的函数。
       * 参数三funct：在成功放置时执行的功能。
       * 参数四dragElement：可选，用于拖动预览的DOM节点
       * 参数五dx：可选，光标和拖动预览之间的水平偏移量
       * 参数六dy：可选，光标和拖动预览之间的垂直偏移量
       * 参数七autoscroll：可选，布尔值，指定是否应该使用自动滚动，默认是mxGraph.autoscroll
       * 参数八scalePreview：可选，布尔值，指定预览元素是否应该按照图形的比例缩放。如果是true，那么偏移量也会被缩放。默认是false。
       * 参数九highlightDropTargets：可选，布尔值，指定dropTargets是否应该高亮显示。默认是true
       * 参数十getDropTarget：可选，函数，用于返回给定位置（x，y）的放置目标。默认值为mxGraph.getCellAt
       */
      setTimeout(() => {
        this.$nextTick(() => {
          mxUtils.makeDraggable(img,graph,funct,undefined,img.getBoundingClientRect().width / 2 * -1,img.getBoundingClientRect().height / 2 * -1)
        })
      },1500)
      return img
    }
  }
};
</script>

<style>
.mxToolbarMode {
  width: 55px;
}
.parent-wrapper > .tool-item {
  position: absolute;
  top: 0;
  right: 0;
  bottom: 0;
  padding: 0;
  width: 200px;
  transition: transform 0.5s, display 0s 0.5s;
  background: #0001;
  overflow: auto;
  transform: translateX(100%);
}
.parent-wrapper > .tool-item.active {
  transform: translateX(0);
}
.tool-wra {
  position: absolute;
  right: 0;
  width: 50px;
  top: 0;
  bottom: 0;
}
.tool-wra-item {
  display: inline-block;
  width: 100%;
  padding: 10px 0;
  border-bottom: 1px solid #999;
  cursor: pointer;
}
.tool-wra-item.active {
  background: coral;
  color: #fff;
}
</style>